package com.jdrx.ocp.service;

import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Maps;
import com.jdrx.logger.bizlogs.BizLoggerService;
import com.jdrx.ocp.beans.commons.BusinessConstants;
import com.jdrx.ocp.beans.commons.MD5Util;
import com.jdrx.ocp.beans.commons.SysConstant;
import com.jdrx.ocp.beans.constans.*;
import com.jdrx.ocp.beans.dto.login.LoginDTO;
import com.jdrx.ocp.beans.dto.login.LoginWeChatDTO;
import com.jdrx.ocp.beans.entity.DeptPO;
import com.jdrx.ocp.beans.entity.RolePO;
import com.jdrx.ocp.beans.entity.UserLoginLogsPO;
import com.jdrx.ocp.beans.entity.UserPO;
import com.jdrx.ocp.beans.entity.util.DeviceUtils;
import com.jdrx.ocp.beans.enums.EUserRoleLevel;
import com.jdrx.ocp.beans.vo.LoginUserVO;
import com.jdrx.ocp.beans.vo.LoginWeChatVO;
import com.jdrx.ocp.beans.vo.UserVO;
import com.jdrx.ocp.config.JWTAuthConfig;
import com.jdrx.ocp.dao.UserDAO;
import com.jdrx.ocp.exception.ValidateCodeException;
import com.jdrx.ocp.utils.IpUtil;
import com.jdrx.ocp.utils.JwtUtil;
import com.jdrx.ocp.utils.UniqueLoginEntity;
import com.jdrx.ocp.utils.ValidateUtils;
import com.jdrx.platform.commons.rest.beans.vo.ResposeVO;
import com.jdrx.platform.commons.rest.exception.BizException;
import com.jdrx.platform.commons.rest.factory.ResponseFactory;
import com.jdrx.sw.sewage.beans.dto.log.AddLogDTO;
import com.jdrx.sw.sewage.beans.vo.LoginStationVO;
import com.jdrx.sw.sewage.dao.DeviceNumSetDAO;
import com.jdrx.sw.sewage.remote.MtLogRemote;
import com.jdrx.sw.sewage.service.LogService;
import com.jdrx.sw.sewage.service.StationServiceImpl;
import com.jdrx.sw.sewage.service.common.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Service
@CacheConfig(cacheNames = "serviceProvider")
public class AdminService {
    private static Logger logger = LoggerFactory.getLogger(AdminService.class);
    private static String ONLINE = "online";
    private static String TOKEN = "token";
    @Autowired
    UserService userService;
    @Autowired
    ResourceService resourceService;
    @Autowired
    RoleService roleService;
    @Autowired
    JWTAuthConfig jwtAuthConfig;
    @Autowired
    RedisService redisService;
    @Autowired
    BizLoggerService bizLoggerService;
    @Autowired
    SettingService settingService;
    @Autowired
    ValidateUtils validateUtils;
    @Autowired
    UserLoginLogsService userLoginLogsService;
    @Autowired
    UserDAO userDAO;
    @Autowired
    UserLoginStatsService userLoginStatsService;
    @Autowired
    DeptService deptService;
    @Autowired
    MtLogRemote mtLogRemote;
    @Autowired
    StationServiceImpl stationService;
    @Autowired
    LogService logService;
    @Autowired
    private DeviceNumSetDAO deviceNumSetDAO;
    @Value("${aioFlag}")
    private String aioFlag;
    
    /**
     * app 登录
     *
     * @param loginDTO
     * @param ipAddr
     * @return
     * @throws BizException
     */
    public LoginUserVO appLogin(LoginDTO loginDTO, String ipAddr, HttpServletRequest request, String tid) throws BizException, ValidateCodeException {
        LoginUserVO loginUserVO = new LoginUserVO();

        // 获取 用户的角色
        List<RolePO> rolePOList = roleService.findRoleByUserId(loginUserVO.getId());

        // 判断是否有领导角色
        List<RolePO> leaderRoleList = rolePOList.stream()
                .filter(t -> ERoleType.LEADER.getType().equals(t.getType()))
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(leaderRoleList)) {
            //loginUserVO.setType(ERoleType.LEADER.getType());
        } else {
            //loginUserVO.setType(ERoleType.STAFF.getType());
        }
        return loginUserVO;
    }

    @Transactional(rollbackFor = Exception.class)
    public LoginUserVO platformLogin(LoginDTO dto, Long tenantId) throws Exception {
        UserPO po = new UserPO();
        po.setName(dto.getUserName());
        po.setPwd(dto.getPassword());
        List<UserVO> list = userDAO.list(po);
        if(CollectionUtils.isEmpty(list)) {
        	throw new BizException("用户名或密码错误");
        }
        
        UserVO userVO = list.get(0);
        userVO.setPwd(null);
        
        LoginUserVO loginUserVO = new LoginUserVO();
        BeanUtils.copyProperties(userVO, loginUserVO);
        
        // 修改登录状态为已登录
        userDAO.updateLoginFlagByName(ELoginFlag.LOGIN.getKey(), dto.getUserName());
        
        // 如果用户权限级别是超级管理员，则远程查询拼接所有站点id、站点名字赋值到stationIds、station
        String stationIds = loginUserVO.getStationIds(), stations = loginUserVO.getStations();
		if (Optional.ofNullable(userVO.getRoleLevel()).orElse(-1) == EUserRoleLevel.SUPER_ADMIN.getKey()) {
			LoginStationVO loginStationVO = stationService.getLoginStation();
			stationIds = Optional.ofNullable(loginStationVO).map(p->p.getStationIds()).orElse(null);
			stations = Optional.ofNullable(loginStationVO).map(p->p.getStation()).orElse(null);
			loginUserVO.setStationIds(stationIds);
			loginUserVO.setStations(stations);
		}
        
        // 登录之后缓存用户信息
        Map<String, Object> cacheUserMap = Maps.newHashMap();
        String tenantName = redisService.getMapField(SysConstant.REDIS_TENANT + tenantId, "companyName");
        cacheUserMap.put("id", loginUserVO.getId() + "");
        cacheUserMap.put("tenantId", tenantId + "");
        cacheUserMap.put("tenantName", tenantName);
        //cacheUserMap.put("dataNode", dataNode);
        cacheUserMap.put("realName", loginUserVO.getRealName());
        cacheUserMap.put("name", loginUserVO.getName());
        cacheUserMap.put("roleLevel", loginUserVO.getRoleLevel() + "");
        cacheUserMap.put("stationIds", stationIds);
        cacheUserMap.put("stations", stations);
        redisService.addMap(SysConstant.REDIS_USER + tenantId + ":" + loginUserVO.getId(), cacheUserMap);
        
		/*mtLogRemote.add(MtLogAddDTO.builder()
				.userId(loginUserVO.getId())
				.user(userVO.getRealName())
				.tenant(tenantName)
				.tenantId(tenantId)
				.event("登陆")
				.terminal("web")
				.description("登录")
				.build());*/
		
		logService.add(AddLogDTO.builder()
				.userId(loginUserVO.getId())
				.user(userVO.getRealName())
				.tenant(tenantName)
				.tenantId(tenantId)
				.event("登陆")
				.terminal("web")
				.description("登录")
				.build());
        
        String token = JwtUtil.generateToken(jwtAuthConfig.getSigningKey(), cacheUserMap, jwtAuthConfig.getExpiredSeconds());
        loginUserVO.setToken(token);
        loginUserVO.setTenantId(tenantId);
        loginUserVO.setTenantName(tenantName);
        loginUserVO.setType(deviceNumSetDAO.getDeviceNumSet().getType());
        //loginUserVO.setDataNode(dataNode);
        return loginUserVO;
    }

    /**
     * 获取浏览器唯一标识
     *
     * @param browserSymbol
     * @return
     * @throws BizException
     */
    public ResposeVO generateBrowserUniqueId(String browserSymbol) throws BizException {
        List<UniqueLoginEntity> uniqueLoginEntities = JSONArray.parseArray(browserSymbol, UniqueLoginEntity.class);
        if (uniqueLoginEntities == null || uniqueLoginEntities.size() == 0) {
            throw new BizException(EMessageKeyEnum.browser_uniqueId_not_null.getValue());
        }
        uniqueLoginEntities.sort(new Comparator<UniqueLoginEntity>() {
            @Override
            public int compare(UniqueLoginEntity o1, UniqueLoginEntity o2) {
                return o1.getKey().compareTo(o2.getKey());
            }
        });
        StringBuilder stringBuilder = new StringBuilder();
        for (UniqueLoginEntity uniqueLoginEntity : uniqueLoginEntities) {
            stringBuilder.append(uniqueLoginEntity.getKey());
            stringBuilder.append(BusinessConstants.COLON);
            stringBuilder.append(uniqueLoginEntity.getValue());
        }
        stringBuilder.append(BusinessConstants.LOGIN_ENTEY);
        stringBuilder.append(BusinessConstants.COLON);
        String browserUniqueId = MD5Util.string2MD5(stringBuilder.toString());
        return ResponseFactory.ok(browserUniqueId);
    }

    /**
     * redis记录登录用户信息
     *
     * @param loginUserVO
     * @throws BizException
     */
    private void saveLoginUserForRedis(LoginUserVO loginUserVO, String tid) throws BizException {
        try {
            String key = getUserRedisKey(loginUserVO.getId(), tid);
            Map<String, Object> map = redisService.getMap(key);
            if (map != null) {
                map.put(ONLINE, EYesOrNo.YES.getKey().toString());
                map.put(TOKEN, loginUserVO.getToken());
                redisService.setMap(key, map, null);
            } else {
                logger.warn("用户信息缓存失败！");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException(e.getMessage());
        }
    }

    /**
     * 查询用户是否已登录
     *
     * @param userId
     * @return
     */
    public boolean checkUserIsLogin(Long userId, String tid) {
        Map map = redisService.getMap(getUserRedisKey(userId, tid));
        if (map != null && map.get(ONLINE) != null && EYesOrNo.YES.getKey().toString().equals(map.get(ONLINE).toString())) {
            return true;
        }
        return false;
    }

    /**
     * 读取配置，是否允许用户重复登录
     *
     * @return
     */
    public boolean isAllowRepetitionLogin(String tid) throws BizException {
        Object obj = settingService.getSettingByKey(EUserSecurity.REPEAT_LOGIN.getKey(), tid);
        logger.info(String.format("reportLogin:%s", obj));
        if (obj != null && String.valueOf(obj).equals(String.valueOf(EYesOrNo.YES.getKey()))) {
            return true;
        }
        return false;
    }

    /**
     * 获取指定用户的redis存储key
     *
     * @param userId
     * @return
     */
    public String getUserRedisKey(Long userId, String tid) {
        tid = formatTid(tid);
        return "";
    }

    private String getUserOnlineKey(Long userId, String tid) {
        tid = formatTid(tid);
        return "";

    }


    /**
     * 获取指定用户的redis存储key
     *
     * @param phone
     * @return
     */
    private String getUserPhoneRedisKey(String phone) {
        return "";
    }

    /**
     * 获取指定机构的redis存储key
     *
     * @param deptID
     * @return
     */
    private String getDeptRedisKey(Long deptID, String tid) {
        tid = formatTid(tid);
        return "";
    }

    private String formatTid(String tid) {
        if (StringUtils.isEmpty(tid)) {
            tid = "";
        } else {
            if (tid.indexOf(",") > 0) {
                String[] tids = tid.split(",");
                for (String id : tids) {
                    if (StringUtils.isNotEmpty(id)) {
                        tid = id;
                        break;
                    }
                }
            }
            tid = tid + ":";
        }
        return tid;
    }

    /**
     * 退出登录时清理登录信息
     *
     * @param userId
     * @return
     */
    public boolean logout(Long userId, HttpServletRequest request, Long tid) {
        try {
			/*Map map = redisService.getMap(getUserRedisKey(userId, tid));
			if (map != null) {
			    map.put(ONLINE, EYesOrNo.NOT.getKey().toString());
			    redisService.setMap(getUserRedisKey(userId, tid), map, null);
			    removeUserSession(request, userId);
			}*/
            
			/*mtLogRemote.add(MtLogAddDTO.builder()
					.userId(userId)
					.user(redisService.getMapField(SysConstant.REDIS_USER + tid + ":" + userId, "realName"))
					.tenant(redisService.getMapField(SysConstant.REDIS_USER + tid + ":" + userId, "tenantName"))
					.tenantId(tid)
					.event("退出")
					.terminal("web")
					.description("退出")
					.build());*/
        } catch (Exception e) {
            logger.warn(String.format("用户退出异常：s%", e.getMessage()));
        }
        return true;
    }

    /**
     * 退出登录时清理登录信息
     *
     * @param userId
     * @return
     */
    public boolean logout(Long userId, String tid) {
        try {
            Map map = redisService.getMap(getUserRedisKey(userId, tid));
            if (map != null) {
                map.put(ONLINE, EYesOrNo.NOT.getKey().toString());
                redisService.setMap(getUserRedisKey(userId, tid), map, null);
                removePcUserSession(userId);
            }
        } catch (Exception e) {
            logger.warn(String.format("用户退出异常：s%", e.getMessage()));
        }
        return true;
    }

    /**
     * 用户停用或删除时清理登录信息
     *
     * @param userId
     * @return
     */
    public boolean clearLoginUserInfo(Long userId, String tid) {
        try {
            redisService.del(getUserRedisKey(userId, tid));
        } catch (Exception e) {
            logger.warn(String.format("清理登录信息异常：s%", e.getMessage()));
        }
        return true;
    }

    public void storageRedisUser(List<UserPO> list, String tid) {
        list.forEach(row -> {
            addRedisUser(row, tid);
        });
    }

    public void addRedisUser(UserPO userPO, String tid) {
        String key = getUserRedisKey(userPO.getId(), tid);
        Map map = redisService.getMap(key);
        if (map == null) {
            map = new HashMap(7);
            map.put(ONLINE, EYesOrNo.NOT.getKey().toString());
        }
        map.put("id", String.valueOf(userPO.getId()));
        map.put("deptId", String.valueOf(userPO.getDeptId()));
        map.put("realName", userPO.getRealName());
        map.put("name", userPO.getName());
        map.put("pwd", userPO.getPwd());
        map.put("phone", Optional.ofNullable(userPO.getPhone()).orElse(""));
        map.put("email", Optional.ofNullable(userPO.getEmail()).orElse(""));
        map.put("isAdmin", String.valueOf(userPO.getIsAdmin()));
        map.put("isSystem", String.valueOf(userPO.getIsSystem()));
        Map<String, String> dept = new HashMap<>();
        if (Optional.ofNullable(userPO.getDeptId()).orElse(0L) > 0) {
            dept = redisService.getMap(getDeptRedisKey(userPO.getDeptId(), tid));
        }
        map.put("deptPid", Optional.ofNullable(dept).map(d -> d.get("pid")).orElse("0"));
        map.put("deptName", Optional.ofNullable(dept).map(d -> d.get("name")).orElse(""));
        map.put("delFlag", String.valueOf(userPO.getDelFlag()));
        map.put("status", String.valueOf(userPO.getStatus()));
        if (StringUtils.isNotBlank(userPO.getCompany())) {
            map.put("company", userPO.getCompany());
        }
        if (StringUtils.isNotBlank(userPO.getClassIds())) {
            map.put("classIds", userPO.getClassIds());
        }
        redisService.setMap(key, map, null);
        if (StringUtils.isNotBlank(userPO.getPhone())) {
            redisService.setMap(getUserPhoneRedisKey(userPO.getPhone()), map, null);
        }
    }

    public void storageRedisDept(List<DeptPO> list, String tid) {
        list.forEach(row -> {
            addRedisDept(row, tid);
        });
    }

    public void addRedisDept(DeptPO deptPO, String tid) {
        String key = getDeptRedisKey(deptPO.getId(), tid);
        Map map = redisService.getMap(key);
        if (map == null) {
            map = new HashMap(4);
        }
        map.put("id", String.valueOf(deptPO.getId()));
        map.put("name", deptPO.getName());
        map.put("pid", String.valueOf(deptPO.getPid()));
        redisService.setMap(key, map, null);
    }


    /**
     * 微信端登录
     *
     * @param dto
     * @return
     * @throws BizException
     */
    public LoginWeChatVO loginWeChat(LoginWeChatDTO dto) throws BizException {
        LoginWeChatVO loginWeChatVO = new LoginWeChatVO();
        try {
            //用户登录验证
            UserPO userPO = userDAO.getByOpenId(dto.getOpenId());
            if (userPO == null) {
                throw new BizException(EMessageKeyEnum.user_not_exist.getValue());
            }
            if (userPO.getStatus() == 0) {
                throw new BizException(EMessageKeyEnum.user_disable.getValue());
            }
            if (StringUtils.isBlank(userPO.getOpenId())) {
                throw new BizException("该手机号码还未绑定OPEN ID!");
            }

            Map userInfoMap = Maps.newHashMap();
            userInfoMap.put("id", userPO.getId().toString());//用户id
            userInfoMap.put("realName", userPO.getRealName());
            userInfoMap.put("deptId", userPO.getDeptId());
            String token = JwtUtil.generateToken(jwtAuthConfig.getSigningKey(), userInfoMap, jwtAuthConfig.getExpiredSeconds());

            BeanUtils.copyProperties(userPO, loginWeChatVO);
            loginWeChatVO.setToken(token);
            return loginWeChatVO;
        } catch (Exception e) {
            throw new BizException(e.getMessage());
        }
    }

	/*public boolean validateCode(LoginDTO loginDTO) throws BizException, ValidateCodeException {
	    if (validateUtils.isValidateCodeLogin(loginDTO.getUniqueId(), false, false)) {
	        if (StringUtils.isNotEmpty(loginDTO.getValidateCode()) && validateUtils.validateCodeRight(loginDTO.getUniqueId(), loginDTO.getValidateCode())) {
	            validateUtils.isValidateCodeLogin(loginDTO.getUniqueId(), false, true);
	            return true;
	        } else {
	            throw new ValidateCodeException("请输入正确的验证码！");
	        }
	    }
	    return true;
	}*/

    public void writeLoginLogs(HttpServletRequest request, LoginUserVO userVO) throws BizException {
        try {
            String device = getDevice(request);
            UserLoginLogsPO po = new UserLoginLogsPO();
            po.setUserId(userVO.getId());
            po.setName(userVO.getName());
            po.setRealName(userVO.getRealName());
            po.setLoginIp(IpUtil.getIpAddr(request));
            po.setLoginTime(new Date());
            po.setDevice(device);
            po.setToken(userVO.getToken());
            userLoginLogsService.insert(po);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    private String getDevice(HttpServletRequest request) {
        String device = "";
        if (DeviceUtils.isIOSDevice(request)) {
            device = "IOS";
        } else if (DeviceUtils.isAndroidDevice(request)) {
            device = "Android";
        } else if (DeviceUtils.isWeChat(request)) {
            device = "WeChat";
        } else if (DeviceUtils.isMobileDevice(request)) {
            device = "Mobile";
        } else {
            device = "PC";
        }
        return device;
    }

    /**
     * 设置用户会话
     *
     * @param request
     * @param userVO
     */
    private void setUserSession(HttpServletRequest request, LoginUserVO userVO) {
		/*redisService.set(redisConfig.getSessionPath() + getDevice(request) + ":" + userVO.getId(),
		        new Date(),
		        Long.valueOf(redisConfig.getSessionExpired()));*/
    }

    /**
     * 注销会话
     *
     * @param request
     * @param uId
     */
    private void removeUserSession(HttpServletRequest request, Long uId) {
        //redisService.del(redisConfig.getSessionPath() + getDevice(request) + ":" + uId);
    }

    /**
     * 注销会话
     *
     * @param uId
     */
    private void removePcUserSession(Long uId) {
        //redisService.del(redisConfig.getSessionPath() + "PC" + ":" + uId);
    }

    /**
     * 租户基础数据缓存
     *
     * @param tid
     */
    public void setCache(String tid) {
        try {
            String userRedisKey = getUserRedisKey(0L, tid).replace(":" + tid + ":0", ":" + tid);
            Object obj = redisService.getObj(userRedisKey);
            if (obj == null) {
                userService.storageRedisUser(tid);
                deptService.storageRedisDept(tid);
                resourceService.storageRedisResource(tid);
                settingService.keyMap(tid);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

}